package com.bosssoft.cloud.wechat.infrastructure.advice;

import com.alibaba.dubbo.rpc.RpcException;
import com.bosssoft.cloud.exception.EIPSException;
import com.bosssoft.cloud.wechat.infrastructure.bean.response.R;
import com.bosssoft.cloud.wechat.infrastructure.enums.ErrEnum;
import com.bosssoft.cloud.wechat.infrastructure.enums.ResultEnum;
import com.bosssoft.cloud.wechat.infrastructure.exception.BaseException;
import com.bosssoft.cloud.wechat.infrastructure.exception.BusinessException;
import com.bosssoft.cloud.wechat.infrastructure.exception.StackTrace;
import com.bosssoft.cloud.wechat.infrastructure.exception.SystemException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;


/**
 * 全局Controller增强
 * 异常捕获处理
 * <p>
 *
 * @author wcy create on 2021/5/17 17:45 下午
 */

@Slf4j
@RestControllerAdvice
public class ExceptionControllerAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return filter(methodParameter);
    }

    /**
     * 根据返回类型来判断是否需要进行后续操作
     *
     * @param methodParameter methodParameter
     * @return 是否继续处理
     */
    private boolean filter(MethodParameter methodParameter) {
        // 在此过滤验证码图片等不处理的情况
        return true;
    }


    /**
     * @param returnValue           返回值
     * @param returnType            Controller方法返回类型
     * @param selectedContentType   t
     * @param selectedConverterType t
     */
    @Override
    public Object beforeBodyWrite(Object returnValue, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        //获取返回值类型
        String returnClassType = returnType.getParameterType().getSimpleName();
        // eg: if("void".equals(returnClassType)) -> 如果返回值类型为void，则默认返回成功
        if ("R".equals(returnClassType))
            return returnValue;
        //一定要转换为String，否则会报错
        return new R<>(ResultEnum.SUCCESS, returnValue);
    }


    /**
     * 全局异常捕捉处理
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R<?> errorHandler(Exception e) {
        e.printStackTrace();
        return new R<>(ErrEnum.B0001);
    }

    @ExceptionHandler(value = BusinessException.class)
    public R<?> businessException(BusinessException e) {
        return new R<>(e.getErrEnum(), e.getMessage());
    }

    @ExceptionHandler(value = BaseException.class)
    public R<?> baseException(BaseException e) {
        if (e instanceof StackTrace)
            e.printStackTrace();
        return new R<>(e.getErrEnum(), e.getMessage());
    }

    @ExceptionHandler(value = SystemException.class)
    public R<?> systemException(SystemException e) {
        e.printStackTrace();
        return new R<>(e.getErrEnum(), e.getMessage());
    }

    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    public R<?> httpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        return new R<>(ErrEnum.A0324, e.getMessage());
    }

    /* ----------------------- 第三方 ------------------------------ */

    @ExceptionHandler(value = EIPSException.class)
    public R<?> AlipayWebHandler(EIPSException ex) {
        String message = ex.getMessage();
        log.error("公众服务异常=>" + message);
        if (message.contains("随机数错误")) {
            message = "校验码错误";
        }
        return new R<>(ErrEnum.C0001, message);
    }

    @ExceptionHandler(value = RpcException.class)
    public R<?> rpcExceptionHandler(RpcException ex) {
        log.error("dubbo服务异常=>" + ex.getMessage());
        return new R<>(ErrEnum.C0110);
    }
}